package com.pictavore.gui;

import com.google.inject.Inject;
import com.pictavore.image.PVImage;
import com.pictavore.image.ImageMessage;
import com.pictavore.message.Message;
import com.pictavore.message.MessageListener;
import com.pictavore.message.MessageResponder;
import com.pictavore.message.MessageType;
import com.pictavore.message.Messenger;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import com.sun.media.jai.widget.*;

/**
 *
 * @author dvenable
 */
public class DisplayPanel extends JPanel {

    enum ROIMode {

        None, Growing, Dragging
    };
    Messenger messenger;
    ImgCnv2 imageCanvas;
    JScrollPane jsp;
    JSlider slider;
    PVImage currentImage = null;
    double scaleFactor;
    Rectangle roiRect;
    ROIMode roiMode = ROIMode.None;
    int lastx = -1;
    int lasty = -1;
    int dx = 0;
    int dy = 0;

    @Inject
    public DisplayPanel(Messenger messenger) {
        super();

        this.messenger = messenger;

        setLayout(new BorderLayout());

        imageCanvas = new ImgCnv2();
        jsp = new JScrollPane(imageCanvas);
        jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        add(jsp, BorderLayout.CENTER);

        slider = new JSlider(JSlider.VERTICAL, -100, 100, 0);
        add(slider, BorderLayout.WEST);

        roiRect = new Rectangle(0, 0, 0, 0);

        // <editor-fold defaultstate="collapsed" desc="Messenger listeners/responders">
        messenger.addListener(ImageMessage.NEW_IMAGE, new MessageListener() {
            public void onMessage(Message msg) {
                currentImage = (PVImage) msg.getParameters()[0];
                imageCanvas.setImage(currentImage);
                repaint();
            }
        });
        messenger.addListener(ImageMessage.IMAGE_UPDATED, new MessageListener() {
            public void onMessage(Message msg) {
                currentImage = (PVImage) msg.getParameters()[0];
                imageCanvas.setImage(currentImage);
                imageCanvas.repaint();
            }
        });
        messenger.addListener(ImageMessage.DISPLAY_UPDATED, new MessageListener() {
            public void onMessage(Message msg) {
                currentImage = (PVImage) msg.getParameters()[0];
                imageCanvas.setImage(currentImage);
                imageCanvas.repaint();
            }
        });
        messenger.addResponder(ImageMessage.PRIMARY_IMAGE, new MessageResponder() {
            public Object respond(MessageType type, Object sender, Object... params) {
                return imageCanvas.getImage();
            }
        });

        // </editor-fold>

        slider.addChangeListener(new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                int val = slider.getValue();
                if (val >= 0) {
                    scaleFactor = 1.0 + (double) val / (double) 100 * 10;
                } else {
                    scaleFactor = 1.0 / (1.0 + (double) val / (double) -100 * 10);
                }
                imageCanvas.setScaleFactor(scaleFactor);
                getParent().repaint();
            }
        });


        // <editor-fold defaultstate="collapsed" desc="Event handlers">
        imageCanvas.addMouseMotionListener(new MouseMotionAdapter() {

            @Override
            public void mouseDragged(MouseEvent e) {
                if (currentImage == null || e.getButton() == MouseEvent.NOBUTTON) {
                    return;
                }
//                BufferedImage bimg;
//                int x = e.getX();
//                int y = e.getY();
//                Rectangle rct = new Rectangle(x - 128, y - 96, 256, 192);
//                try
//                {
//                    bimg = currentImage.getStretchedWindow(rct);
//                } catch (Exception ex)
//                {
//                    bimg = null;
//                }
                int x = e.getX();
                int y = e.getY();
                if (roiMode == ROIMode.Dragging) {
                    roiRect.x = x - dx;
                    roiRect.y = y - dy;
                } else if (roiMode == ROIMode.Growing) {
                    roiRect.width = x - roiRect.x + 1;
                    roiRect.height = y - roiRect.y + 1;
                }
                if (roiRect.x < 0) {
                    roiRect.x = 0;
                }
                if (roiRect.y < 0) {
                    roiRect.y = 0;
                }
                if ((roiRect.x + roiRect.width) > currentImage.Width) {
                    roiRect.x = currentImage.Width - roiRect.width;
                }
                if ((roiRect.y + roiRect.height) > currentImage.Height) {
                    roiRect.y = currentImage.Height - roiRect.height;
                }
                imageCanvas.setROI(roiRect);
                imageCanvas.repaint();
                BufferedImage bimg = null;
                try {
                    bimg = currentImage.getStretchedWindow(roiRect);
                } catch (Exception ex) {
                    bimg = null;
                }
                DisplayPanel.this.messenger.sendMessage(ImageMessage.NEW_SEGMENT, this, bimg);
            }
        });
        imageCanvas.addMouseListener(new MouseAdapter() {

            @Override
            public void mousePressed(MouseEvent e) {
//                BufferedImage bimg;
//                int x = e.getX();
//                int y = e.getY();
//                Rectangle rct = new Rectangle(x - 128, y - 96, 256, 192);
//                currentImage = (PVImage) Messenger.SendRequest("PrimaryImage", this, null);
//                try
//                {
//                    bimg = currentImage.getStretchedWindow(rct);
//                } catch (Exception ex)
//                {
//                    bimg = null;
//                }
//                Messenger.SendMessage("NewSegment", this, bimg);

                int x = e.getX();
                int y = e.getY();
                if (roiRect.contains(x, y)) {
                    roiMode = ROIMode.Dragging;
                    dx = x - roiRect.x;
                    dy = y - roiRect.y;
                } else {
                    roiMode = ROIMode.Growing;
                    roiRect.x = x;
                    roiRect.y = y;
                    roiRect.width = 1;
                    roiRect.height = 1;
                }
                imageCanvas.setROI(roiRect);
                imageCanvas.repaint();
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                roiMode = ROIMode.None;
                lastx = lasty = -1;
                imageCanvas.repaint();
                BufferedImage bimg = null;
                try {
                    bimg = currentImage.getStretchedWindow(roiRect);
                } catch (Exception ex) {
                    bimg = null;
                }
                DisplayPanel.this.messenger.sendMessage(ImageMessage.NEW_SEGMENT, this, bimg);
            }
        });

    // </editor-fold>

    }

    public void setImage(PVImage pvi) {
        currentImage = pvi;
        imageCanvas.setImage(pvi);
    }
}


// <editor-fold defaultstate="collapsed" desc="BufferedImage-based">
class ImgCnv extends JPanel {

    PVImage pvi;
    double scaleFactor;

    public ImgCnv() {
        super();
    }

    public void setScaleFactor(double sf) {
        scaleFactor = sf;
        getParent().invalidate();
    }

    public void setImage(PVImage pvi) {
        this.pvi = pvi;
        scaleFactor = 1.0;
        Dimension dim = new Dimension(pvi.wrk.getWidth(), pvi.wrk.getHeight());
        setSize(dim);
        setPreferredSize(dim);
    }

    public PVImage getImage() {
        return pvi;
    }

    @Override
    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.scale(scaleFactor, scaleFactor);

        if (pvi != null && pvi.wrk != null) {
            g.drawImage(pvi.wrk, 0, 0, null);
        }
    }
}

// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="TIledImage-based">
class ImgCnv2 extends DisplayJAI {

    PVImage pvi;
    double scaleFactor = 0;
    Rectangle roi;

    public ImgCnv2() {
        super();
    }

    public void setScaleFactor(double sf) {
        scaleFactor = sf + .001;
        getParent().invalidate();
    }

    public void setImage(PVImage pvi) {
        this.pvi = pvi;
//        scaleFactor = 1.0;
        Dimension dim = new Dimension(pvi.wrk2.getWidth(), pvi.wrk2.getHeight());
        setSize(dim);
        setPreferredSize(dim);
        set(pvi.wrk2);
        repaint();
    }

    public PVImage getImage() {
        return pvi;
    }

    public void setROI(Rectangle r) {
        roi = r;
    }

    @Override
    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        if (scaleFactor != 0) {
//            System.out.println("ScaleFactor: " + scaleFactor);
            try {
                g2d.scale(scaleFactor, scaleFactor);
            } catch (Exception ex) {
                int k = 0;
            }
        }
        super.paint(g);

        if (roi != null && roi.getWidth() != 0 && roi.getHeight() != 0) {
            g.setColor(Color.yellow);
            g.drawRect(roi.x, roi.y, roi.width, roi.height);
        }

    }
}

// </editor-fold>